2621. Kings Tour

 

Chess is a game played on a board of eight rows and eight columns of squares. Columns are marked a to h from left to right, and rows are numbered 1 to 8 from bottom to top. To play chess, you have to understand the paths by which pieces can attack. One of the pieces is a pawn. A pawn attacks diagonally, one square upward and to the left or right. For example, if a pawn is on c3, it threatens d4 and b4. Another piece is the king. A king can move or attack one square in any direction vertically, horizontally or diagonally. When a pawn or king attacks a square, it moves to that square and captures the piece occupying that square.

You are given the starting positions of a king, pawn A, and pawn B. Find the minimum number of moves necessary for the king to capture pawn A. The king is not allowed to move to squares threatened by either of the pawns, and it is not allowed to move outside of the board. The king can capture pawn B but does not have to. Neither of the pawns will move.

 

Input. Consists of multiple test cases. Each line describes one test case that contains the starting positions of a king, pawn A and pawn B. Each position contains exactly two characters. The first character is the column (a h) and the second character is the row (1 8). All three positions will be distinct. The king's starting position will not be threatened by a pawn.

 

Output. For each test case print in a separate line the minimum number of moves necessary for the king to capture pawn A.

 

Sample input

Sample output

c4 e6 d5

g2 a8 a2

a3 b1 c1

2

6

7

 

 

SOLUTION

graphs breadth first search

 

Algorithm analysis

Рассмотрим два варианта движения короля:

1. Король направляется к пешке А несмотря на положение пешки В и съедает ее;

2. Король направляется к пешке В, съедает ее и потом двигается к пешке А.

В обоих случаях при движении короля используется кратчайший путь, который находится поиском в ширину. Находим наименьшее количество ходов в первом и во втором случаях и возвращаем наименьшее среди них значение. Второй случай необходим, например, если изначально пешка А находится под ударом пешки B.

В поля, находящиеся под ударом пешек, изначально поставим значения 1000. Таким образом при поиске в ширину король на них не зайдет. Начальные положения короля и двух пешек занесем соответственно в переменные (kx, ky), (pax, pay), (pbx, pby). Запустим bfs(kx, ky). Занесем в переменные a и b наименьшее число ходов, которыми можно добраться до пешки А и В соответственно: a = m[pax][pay], b = m[pbx][pby]. Если пешка В сбивается, то следует запустить bfs(pbx, pby), найдя таким образом кратчайший путь от пешки В до А. Добавим к b значение m[pax][pay] после второго вызова bfs. Таким образом в a содержится длина кратчайшего пути короля до достижения цели без сбивания пешки В, а в b – со сбиванием. Вычисляем меньшее значение среди a и b.

 

Algorithm realization

Шахматную доску храним в массиве m. Очередь пар d используется для поиска в ширину и содержит координаты полей шахматной доски (x, y).  Массивы xx и yy описывают возможные ходы короля: из клетки (i, j) король может пойти в любую из клеток (i + xx[k], j + yy[k]), где 1 ≤ k ≤ 8.

 

int m[10][10];

deque<pair<int,int> > d;

int xx[8] = {1, 1, 1, -1, -1, -1, 0, 0};

int yy[8] = {-1, 0, 1, -1, 0, 1, 1, -1};

 

Функция cango проверяет, не находится ли поле (x, y) за границами шахматной доски.

 

int cango(int x, int y)

{

  if ((x < 1) || (x > 8) || (y < 1) || (y > 8) || (m[x][y] >= 0))

    return 0;

  return 1;

}

 

Функция bfs реализует поиск в ширину из клетки (x, y). С ее помощью ищем кратчайший путь короля до каждой из пешек.

 

void bfs(int x, int y)

{

  m[x][y] = 0;

  d.push_back(make_pair(x,y));

  while(!d.empty())

  {

    pair<int,int> temp = d[0]; d.pop_front();

 

Перебираем все возможные ходы короля.

 

    for(int i = 0; i < 8; i++)

    {

      int dx = temp.first + xx[i];

      int dy = temp.second + yy[i];

      if (cango(dx, dy))

      {

        m[dx][dy] = m[temp.first][temp.second] + 1;

        d.push_back(make_pair(dx, dy));

      }

    }

  }

}

 

Функция attackPawns возвращает наименьшее количество ходов, за которое король сможет побить пешку A.

 

int attackPawns(void)

{

  memset(m,-1,sizeof(m));

 

В поля, находящиеся под ударом пешек, поставим значения 1000. Это делается для того, чтобы при поиске в ширину король в них не зашел.

 

  m[pax-1][pay+1] = m[pax+1][pay+1] = 1000;

  m[pbx-1][pby+1] = m[pbx+1][pby+1] = 1000;

  bfs(kx,ky);

 

До пешки А король может добраться минимум за а ходов, а до пешки B за b ходов.

 

  int a = m[pax][pay], b = m[pbx][pby];

  memset(m,-1,sizeof(m));

  m[pax-1][pay+1] = m[pax+1][pay+1] = 1000;

 

Вычисляем кратчайший путь от пешки В до пешки А.

 

  bfs(pbx,pby); b += m[pax][pay];

 

В переменной a содержится длина кратчайшего пути короля до пешки A без сбивания пешки В, а в переменной b с ее сбиванием. Возвращаем меньшее значение среди a и b.

 

  return (a < b) ? a : b;

}

 

Основная часть программы. Читаем входные данные. Находим и выводим ответ.

 

while(scanf("%c%c %c%c %c%c\n",&kx, &ky, &pax, &pay, &pbx, &pby) == 6)

{

  kx -= 'a' - 1; ky -= '1' - 1; pax -= 'a' - 1; pay -= '1' - 1;

  pbx -= 'a' - 1; pby -= '1' - 1;

  res = attackPawns();

  printf("%d\n",res);

}